package cn.edu.fzu.delivery.handler.impl;

import cn.edu.fzu.delivery.domain.entity.SysUser;
import cn.edu.fzu.delivery.filter.DeliveryFilter;
import cn.edu.fzu.delivery.filter.DeliveryFilterDto;
import cn.edu.fzu.delivery.handler.DeliveryError;
import cn.edu.fzu.delivery.handler.DeliveryHandler;
import cn.edu.fzu.delivery.handler.DeliverySession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 快递员过滤处理器
 *
 * @author fangxin
 * @date 2022/11/7
 */
@Component("courierFilterHandler")
public class CourierFilterHandler implements DeliveryHandler {

    private static final Logger  log = LoggerFactory.getLogger(CourierFilterHandler.class);

    @Resource
    private List<DeliveryFilter> deliveryFilters;

    @Resource
    private ExecutorService      threadPool;

    @Override
    public boolean process(DeliverySession session) {
        final DeliveryFilterDto dto = new DeliveryFilterDto();

        // 构建一个为快递员过滤器准备数据的任务队列
        List<Callable<Boolean>> tasks = new ArrayList<>(deliveryFilters.size());
        for (final DeliveryFilter item : deliveryFilters) {
            tasks.add(new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                    return item.prepare(session, dto);

                }
            });
        }

        // 并行执行任务
        List<Future<Boolean>> futures;
        try {
            futures = threadPool.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            session.setError(DeliveryError.GLOBAL_FILTER_INTERRUPTED);
            return false;
        }

        DeliveryFilter filter;
        List<DeliveryFilter> filters = new LinkedList<>();
        for (int i = 0; i < deliveryFilters.size(); i++) {
            filter = deliveryFilters.get(i);
            try {
                if (futures.get(i).get()) {
                    filters.add(filter);
                }
            } catch (Exception e) {
                log.error("courier filter handle error.", e);
            }
        }

        SysUser sysUser;
        Iterator<SysUser> it = session.getDeliveryManPool().iterator();
        while (it.hasNext()) {
            sysUser = it.next();
            for (DeliveryFilter item : filters) {
                if (item.filter(sysUser, dto)) {
                    it.remove();
                    break;
                }
            }
        }

        if (session.getDeliveryManPool().isEmpty()) {
            session.setError(DeliveryError.NO_DELIVERYMAN);
            return false;
        }

        return true;
    }
}
